Next | Prev | Top | Contents | Index

Appendix A: Code Example for Index Texture Extension


#include <windows.h>
#include <math.h>
#include <GL/gl.h>

#if !defined(M_PI)
#define M_PI 3.14159265F
#endif

char *className = "OpenGL";
char *windowName = "Color Index Texture";
int winX, winY;
int winWidth, winHeight;

HDC hDC;
HGLRC hGLRC;
HPALETTE hPalette;

void (*idleFunc)(HDC hDC);
BOOL textureReplace = FALSE;

/* struct used to manage color ramps */
struct colorIndexState {
    GLfloat amb[3];     /* ambient color / bottom of ramp */
    GLfloat diff[3];    /* diffuse color / middle of ramp */
    GLfloat spec[3];    /* specular color / top of ramp */
    GLfloat ratio;      /* ratio of diffuse to specular in ramp */
    GLint indexes[3];   /* where ramp was placed in palette */
};

#define NUM_COLORS (sizeof(colors) / sizeof(colors[0]))
struct colorIndexState colors[] = {
    {
        { 0.0F, 0.0F, 0.0F },
        { 0.1F, 0.6F, 0.3F },
        { 1.0F, 1.0F, 1.0F },
        0.75F, { 0, 0, 0 },
    },
    {
        { 0.0F, 0.0F, 0.0F },
        { 0.0F, 0.2F, 0.5F },
        { 1.0F, 1.0F, 1.0F },
        0.75F, { 0, 0, 0 },
    },
    {
        { 0.0F, 0.05F, 0.05F },
        { 0.6F, 0.0F, 0.8F },
        { 1.0F, 1.0F, 1.0F },
        0.75F, { 0, 0, 0 },
    },
};

void
drawTorus(void)
{
    int numMajor = 32;
    int numMinor = 24;
    float majorRadius = 0.6F;
    float minorRadius = 0.2F;
    double majorStep = 2.0F*M_PI / numMajor;
    double minorStep = 2.0F*M_PI / numMinor;
    int i, j;

    for (i=0; i<numMajor; ++i) {
        double a0 = i * majorStep;
        double a1 = a0 + majorStep;
        GLfloat x0 = (GLfloat) cos(a0);
        GLfloat y0 = (GLfloat) sin(a0);
        GLfloat x1 = (GLfloat) cos(a1);
        GLfloat y1 = (GLfloat) sin(a1);

        glBegin(GL_TRIANGLE_STRIP);
        for (j=0; j<=numMinor; ++j) {
            double b = j * minorStep;
            GLfloat c = (GLfloat) cos(b);
            GLfloat r = minorRadius * c + majorRadius;
            GLfloat z = minorRadius * (GLfloat) sin(b);

            glNormal3f(x0*c, y0*c, z/minorRadius);
            glTexCoord2f(i/(GLfloat) numMajor, j/(GLfloat) numMinor);
            glVertex3f(x0*r, y0*r, z);


            glNormal3f(x1*c, y1*c, z/minorRadius);
            glTexCoord2f((i+1)/(GLfloat)numMajor, j/(GLfloat)numMinor);
            glVertex3f(x1*r, y1*r, z);
        }
        glEnd();
    }
}

void setCheckTexture(void)
{
    int texWidth = 64;
    int texHeight = 64;
    GLubyte *texPixels, *p;
    int texSize;
    int i, j;

    texSize = texWidth*texHeight*1*sizeof(GLubyte);
    if (textureReplace) {
        glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
    } else {
        glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD);
    }

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

    texPixels = (GLubyte *) malloc(texSize);
    if (texPixels == NULL) {
        return;
    }

    p = texPixels;
    for (i=0; i<texHeight; ++i) {
        for (j=0; j<texWidth; ++j) {
            int rampIndex = textureReplace ? 1 : 0;
            if ((i ^ j) & 4) {
                *p = colors[0].indexes[rampIndex] & 0xff;
            } else {
                *p = colors[1].indexes[rampIndex] & 0xff;
            }
            p += 1;
        }
    }
glTexImage2D(GL_TEXTURE_2D, 0, GL_COLOR_INDEX8_EXT,
                 texWidth, texHeight, 0,
                 GL_COLOR_INDEX, GL_UNSIGNED_BYTE, texPixels);

    free(texPixels);
}

/*****************************************************************/

void
setProjection(void)
{
    GLfloat aspect = (GLfloat) winWidth / (GLfloat) winHeight;

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glFrustum(-0.5F*aspect, 0.5F*aspect, -0.5F, 0.5F, 1.0F, 3.0F);
    glMatrixMode(GL_MODELVIEW);
}

void
setMaterial(void)
{
    GLfloat matDiff[4] = { 0.65F, 0.05F, 0.20F, 0.60F };
    GLfloat matSpec[4] = { 0.50F, 0.50F, 0.50F, 1.00F };
    GLfloat matShine = 20.00F;
    GLint indexes[3];

    glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, matDiff);
    glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, matSpec);
    glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, matShine);

    indexes[0] = 0;
    indexes[1] = colors[0].indexes[1] - colors[0].indexes[0];
    indexes[2] = colors[0].indexes[2] - colors[0].indexes[0];
    glMaterialiv(GL_FRONT_AND_BACK, GL_COLOR_INDEXES, indexes);
}

void
init(HDC hDC)
{
    GLfloat light0Pos[4] = { 0.70F, 0.70F, 1.25F, 0.00F };

    glClearColor(colors[2].diff[0], colors[2].diff[1], 
                colors[2].diff[2], 1.0F);
    glClearIndex((GLfloat) colors[2].indexes[1]);

    setProjection();
    glTranslatef(0.0F, 0.0F, -2.0F);

    setMaterial();

    glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
    glLightfv(GL_LIGHT0, GL_POSITION, light0Pos);
    glEnable(GL_LIGHT0);

    glEnable(GL_LIGHTING);
    glEnable(GL_DEPTH_TEST);

    setCheckTexture();
    glEnable(GL_TEXTURE_2D);
}

void resize(HDC hDC)
{
    setProjection();
    glViewport(0, 0, winWidth, winHeight);
}

void doRedraw(HDC hDC)
{
    static GLfloat x, y, z;

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glPushMatrix();
    glRotatef(x, 1.0F, 0.0F, 0.0F);
    glRotatef(y, 0.0F, 1.0F, 0.0F);
    glRotatef(z, 0.0F, 0.0F, 1.0F);

    drawTorus();

    glPopMatrix();

    SwapBuffers(hDC);

    x += 5.0F;
    if (x > 360.0F) x -= 360.0F;
    y += 7.0F;
    if (y > 360.0F) y -= 360.0F;
    z += 9.0F;
    if (z > 360.0F) z -= 360.0F;
}

void redraw(HDC hDC)
{
}

/*****************************************************************/

void setupPalette(HDC hDC)
{
    PIXELFORMATDESCRIPTOR pfd;
    LOGPALETTE* pPal;
    int pixelFormat = GetPixelFormat(hDC);
    int paletteSize;

    DescribePixelFormat(hDC, pixelFormat, 
                     sizeof(PIXELFORMATDESCRIPTOR), &pfd);
    if (!(pfd.dwFlags & PFD_NEED_PALETTE ||
          pfd.iPixelType == PFD_TYPE_COLORINDEX))
    {
        return;
    }

    paletteSize = 1 << pfd.cColorBits;
    pPal = (LOGPALETTE*)
        malloc(sizeof(LOGPALETTE) + paletteSize * 
                                 sizeof(PALETTEENTRY));
    pPal->palVersion = 0x300;
    pPal->palNumEntries = paletteSize;

    if (pfd.iPixelType == PFD_TYPE_RGBA) {
        /*
        ** Fill palette with an RGB color ramp
        */
        int redMask = (1 << pfd.cRedBits) - 1;
        int greenMask = (1 << pfd.cGreenBits) - 1;
        int blueMask = (1 << pfd.cBlueBits) - 1;
        int i;

        for (i=0; i<paletteSize; ++i) {
            pPal->palPalEntry[i].peRed =
                    (((i >> pfd.cRedShift) & redMask) * 255) / redMask;
            pPal->palPalEntry[i].peGreen =
                    (((i >> pfd.cGreenShift) & greenMask) * 255)/ 
                                                            greenMask;
            pPal->palPalEntry[i].peBlue =
                    (((i >> pfd.cBlueShift) & blueMask) * 255)/
                                                            blueMask;
            pPal->palPalEntry[i].peFlags = 0;
        }
    } else {
        /*
        ** Fill palette with Color Index color ramps.
        */
        int numRamps = NUM_COLORS;
        int rampSize = (paletteSize - 20) / numRamps;
        int extra = (paletteSize - 20) - (numRamps * rampSize);
        int i, r;

        /*
        ** Setup the logical palette so that it can be realized as
        ** an identity palette
        */

        /* start with a copy of the current system palette */
        GetSystemPaletteEntries(hDC, 0, paletteSize,
                             &pPal->palPalEntry[0]);

        /* fill in non-static entries with desired colors */
        for (r=0; r<numRamps; ++r) {
            int rampBase = r * rampSize + 10;
            PALETTEENTRY *pe = &pPal->palPalEntry[rampBase];
            int diffSize = (int) (rampSize * colors[r].ratio);
            int specSize = rampSize - diffSize;

            for (i=0; i<rampSize; ++i) {
                GLfloat *c0, *c1;
                GLint a;

                if (i < diffSize) {
                    c0 = colors[r].amb;
                    c1 = colors[r].diff;
                    a = (i * 255) / (diffSize - 1);
                } else {
                    c0 = colors[r].diff;
                    c1 = colors[r].spec;
                    a = ((i - diffSize) * 255) / (specSize - 1);
                }

                pe[i].peRed = (BYTE) (a * (c1[0] - c0[0]) + 
                                    255 * c0[0]);
                pe[i].peGreen = (BYTE) (a * (c1[1] - c0[1]) + 
                                     255 * c0[1]);
                pe[i].peBlue = (BYTE) (a * (c1[2] - c0[2]) + 
                                    255 * c0[2]);
                pe[i].peFlags = PC_NOCOLLAPSE;
            }

            colors[r].indexes[0] = rampBase;
            colors[r].indexes[1] = rampBase + (diffSize-1);
            colors[r].indexes[2] = rampBase + (rampSize-1);
        }

        /* initialize any remaining non-static entries */
        for (i=0; i<extra; ++i) {
            int index = numRamps*rampSize+10+i;
            PALETTEENTRY *pe = &pPal->palPalEntry[index];

            pe->peRed = (BYTE) 0;
            pe->peGreen = (BYTE) 0;
            pe->peBlue = (BYTE) 0;
            pe->peFlags = PC_NOCOLLAPSE;
        }
    }

    hPalette = CreatePalette(pPal);
    free(pPal);

    if (hPalette) {
        SelectPalette(hDC, hPalette, FALSE);
        RealizePalette(hDC);
    }
}

void setupDC(HDC hDC)
{
    PIXELFORMATDESCRIPTOR pfd = {
        sizeof(PIXELFORMATDESCRIPTOR),  /* size of this pfd */
        1,                        /* version num */
        PFD_DRAW_TO_WINDOW |        /* support window */
        PFD_SUPPORT_OPENGL |        /* support OpenGL */
        PFD_DOUBLEBUFFER,           /* support double-buffering */
        PFD_TYPE_COLORINDEX,         /* color index mode */
        8,                        /* 8-bit color depth */
        0, 0, 0, 0, 0, 0,          /* color bits (ignored) */
        0,                        /* no alpha buffer */
        0,                        /* alpha bits (ignored) */
        0,                        /* no accumulation buffer */
        0, 0, 0, 0,               /* accum bits (ignored) */
        16,                       /* depth buffer */
        0,                        /* no stencil buffer */
        0,                        /* no auxiliary buffers */
        PFD_MAIN_PLANE,            /* main layer */
        0,                        /* reserved */
        0, 0, 0,                  /* no layer, visible, damage masks */
    };
    int SelectedPixelFormat;
    BOOL retVal;

    SelectedPixelFormat = ChoosePixelFormat(hDC, &pfd);
    if (SelectedPixelFormat == 0) {
        (void) MessageBox(WindowFromDC(hDC),
                "Failed to find acceptable pixel format.",
                "OpenGL application error",
                MB_ICONERROR | MB_OK);
        exit(1);
    }

    retVal = SetPixelFormat(hDC, SelectedPixelFormat, &pfd);
    if (retVal != TRUE) {
        (void) MessageBox(WindowFromDC(hDC),
                "Failed to set pixel format.",
                "OpenGL application error",
                MB_ICONERROR | MB_OK);
        exit(1);
    }
}

LRESULT APIENTRY
WndProc(
    HWND hWnd,
    UINT message,
    WPARAM wParam,
    LPARAM lParam)
{
    switch (message) {
    case WM_CREATE:
        hDC = GetDC(hWnd);
        setupDC(hDC);
        setupPalette(hDC);
        hGLRC = wglCreateContext(hDC);
        wglMakeCurrent(hDC, hGLRC);
        init(hDC);
        idleFunc = doRedraw;
        return 0;
    case WM_DESTROY:
        idleFunc = NULL;
        if (hGLRC) {
            wglMakeCurrent(NULL, NULL);
            wglDeleteContext(hGLRC);
        }
        ReleaseDC(hWnd, hDC);
        PostQuitMessage(0);
        return 0;
    case WM_SIZE:
        if (hGLRC) {
            winWidth = (int) LOWORD(lParam);
            winHeight = (int) HIWORD(lParam);
            resize(hDC);
            return 0;
        }
    case WM_PALETTECHANGED:
        if (hPalette != NULL && (HWND) wParam != hWnd) {
            UnrealizeObject(hPalette);
            SelectPalette(hDC, hPalette, FALSE);
            RealizePalette(hDC);
            redraw(hDC);
            return 0;
        }
        break;
    case WM_QUERYNEWPALETTE:
        if (hPalette != NULL) {
            UnrealizeObject(hPalette);
            SelectPalette(hDC, hPalette, FALSE);
            RealizePalette(hDC);
            redraw(hDC);
            return TRUE;
        }
        break;
    case WM_PAINT:
        if (hGLRC) {
            PAINTSTRUCT ps;
            BeginPaint(hWnd, &ps);
            redraw(hDC);
            EndPaint(hWnd, &ps);
            return 0;
        }
        break;
    case WM_CHAR:
        switch ((int)wParam) {
        case VK_ESCAPE:
            DestroyWindow(hWnd);
            return 0;
        default:
            break;
        }
        break;
    default:
        break;
    }

    /* Deal with any unprocessed messages */
    return DefWindowProc(hWnd, message, wParam, lParam);
}

int APIENTRY
WinMain(
    HINSTANCE hCurrentInst,
    HINSTANCE hPreviousInst,
    LPSTR lpszCmdLine,
    int nCmdShow)
{
    WNDCLASS wndClass;
    HWND hWnd;
    MSG msg;

    /* Define and register a window class */
    wndClass.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
    wndClass.lpfnWndProc = WndProc;
    wndClass.cbClsExtra = 0;
    wndClass.cbWndExtra = 0;
    wndClass.hInstance = hCurrentInst;
    wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
    wndClass.hbrBackground = GetStockObject(WHITE_BRUSH);
    wndClass.lpszMenuName = NULL;
    wndClass.lpszClassName = className;
    RegisterClass(&wndClass);

    /* Figure out a default size for the window */
    winWidth = GetSystemMetrics(SM_CYSCREEN) / 3;
    winHeight = GetSystemMetrics(SM_CYSCREEN) / 3;

    /* Create a window of the previously defined class */
    hWnd = CreateWindow(
        className,              /* Window class's name */
        windowName,             /* Title bar text */
        WS_OVERLAPPEDWINDOW |   /* The window's style */
        WS_CLIPCHILDREN |
        WS_CLIPSIBLINGS,
        winX, winY,             /* Position */
        winWidth, winHeight,    /* Size */
        NULL,                   /* Parent window's handle */
        NULL,                   /* Menu handle */
        hCurrentInst,           /* Instance handle */
        NULL);                  /* No additional data */

    /* Map the window to the screen */
    ShowWindow(hWnd, nCmdShow);

    /* Force the window to repaint itself */
    UpdateWindow(hWnd);

    /* Message loop */
    while (1) {
        /* execute idle function while no messages to process */
        while (idleFunc &&
               PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) == FALSE)
        {
            (*idleFunc)(hDC);
        }
        if (GetMessage(&msg, NULL, 0, 0) != TRUE) {
            break;
        }
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return msg.wParam;
}



Next | Prev | Top | Contents | Index